/* $RCSFile: General.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.RewriteRules/Tools/General.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:30  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Diagnostics;
using System.Configuration;
using System.Web.Configuration;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Globalization;

using Rewrite.NET;
using AddonNice.Settings;
using AddonNice.Configuration;

using Cache2    =   AddonNice.Settings.Cache.CurrentCache;

namespace AddonNice.RewriteRules.Tools
{
    /// <summary>
    /// General Tool
    /// This Class is responsible for containing all the tools / useful methods
    /// for hanling urls. It also contains legacy methods such as add attribute and KeywordSplitter.
    /// </summary>
	public class General
	{
        public enum PageType { Normal, Register, Logon,Logoff,EditProfile,ChangePwd,RecoverPwd,Special };

        public class PageNode
        {
            public int PageID       =   -1;
            public ADNPageFlags PageLayout =    ADNPageFlags.Normal;
            public string urlName   =   string.Empty;
        }

        public static void Splitter(string[] parts, StringBuilder sb)
        {
            sb.Append("?");
            for (int i = 0; i < parts.GetUpperBound(0); i++)
                sb.AppendFormat("{0}&", parts[i].ToString().Replace(DefaultSplitter, "="));
            sb.Remove(sb.Length -1, 1);
        }

        /// <summary>
        /// Utility to extract Page Type, page location and page name from PageId
        /// </summary>
        public static string CheckPageType(ref int PageId, ref PageType secured,string PortalAlias)
        {
			if ( RewriteTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType BEG PageID: {0}, PortalAlias: '{1}'.",
                    PageId,PortalAlias),RewriteTraceSwitch.Sw.Info);
            string UrlName                  =   string.Empty;
            if ( PortalAlias == string.Empty )
                PortalAlias                 =   Portal.UniqueID;
            else Portal.SetUniqueIDInContext(PortalAlias);
            SortedList<int,PageNode> Lst    =   GetAllUrlName(PortalAlias);
            if ( Lst.ContainsKey(PageId) )
            {
                PageNode nd                 =   Lst[PageId];
                if ( ( nd.PageLayout & ADNPageFlags.IsLoginPage ) == ADNPageFlags.IsLoginPage )
                {
                    string PageIDStr        =   GetPortalSingleCustomSettingsByAlias(PortalAlias,StStr.SiteDefaultLoginPage);
                    if ( PageIDStr == string.Empty )
                        UrlName             =   nd.urlName;
                    else
                    {
                        int newPagID        =   -1;
                        bool okParse        =   int.TryParse(PageIDStr,out newPagID);
                        if ( okParse && Lst.ContainsKey(newPagID) )
                        {
                            PageId          =   newPagID;
                            nd              =   Lst[newPagID];
                            UrlName         =   nd.urlName;
                        }
                    }
                    secured                 =   PageType.Logon;
                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType register pageId: {0}, Secured: {1}, UrlName; {2}",PageId,secured,UrlName),RewriteTraceSwitch.Sw.Info);
                    return UrlName;
                }
                if ( ( nd.PageLayout & ADNPageFlags.IsRegisterPage ) == ADNPageFlags.IsRegisterPage )
                {
                    string PageIDStr        =   GetPortalSingleCustomSettingsByAlias(PortalAlias,StStr.SiteDefaultRegisterPage);
                    if ( PageIDStr == string.Empty )
                        UrlName             =   nd.urlName;
                    else
                    {
                        int newPagID        =   -1;
                        bool okParse        =   int.TryParse(PageIDStr,out newPagID);
                        if ( okParse && Lst.ContainsKey(newPagID) )
                        {
                            PageId          =   newPagID;
                            nd              =   Lst[newPagID];
                            UrlName         =   nd.urlName;
                        }
                    }
                    secured                 =   PageType.Register;
                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType register pageId: {0}, Secured: {1}, UrlName; {2}",PageId,secured,UrlName),RewriteTraceSwitch.Sw.Info);
                    return UrlName;
                }
                if ( ( nd.PageLayout & ADNPageFlags.IsEditProfile ) == ADNPageFlags.IsEditProfile )
                {
                    string PageIDStr        =   GetPortalSingleCustomSettingsByAlias(PortalAlias,StStr.SiteDefaultEditProfilePage);
                    if ( PageIDStr == string.Empty )
                        UrlName             =   nd.urlName;
                    else
                    {
                        int newPagID        =   -1;
                        bool okParse        =   int.TryParse(PageIDStr,out newPagID);
                        if ( okParse && Lst.ContainsKey(newPagID) )
                        {
                            PageId          =   newPagID;
                            nd              =   Lst[newPagID];
                            UrlName         =   nd.urlName;
                        }
                    }
                    secured                 =   PageType.Register;
                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType register pageId: {0}, Secured: {1}, UrlName; {2}",PageId,secured,UrlName),RewriteTraceSwitch.Sw.Info);
                    return UrlName;
                }
                UrlName                     =   nd.urlName;
                if ( RewriteTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType register pageId: {0}, Secured: {1}, UrlName; {2}",PageId,secured,UrlName),RewriteTraceSwitch.Sw.Info);
            }

            switch ( PageId )
            {
                case 23:
                {
                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType logoff page detected PageId: {0}",PageId),RewriteTraceSwitch.Sw.Info);
                    secured                 =   PageType.Logoff;
                    break;
                }
                case 24:
                {
                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType ChangePwd page detected PageId: {0}",PageId),RewriteTraceSwitch.Sw.Info);
                    secured                 =   PageType.ChangePwd;
                    break;
                }
                case 25:
                {
                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType RecoverPwd page detected PageId: {0}",PageId),RewriteTraceSwitch.Sw.Info);
                    secured                 =   PageType.RecoverPwd;
                    break;
                }
                case 26:
                {
                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType EditProfile page detected PageId: {0}",PageId),RewriteTraceSwitch.Sw.Info);
                    secured                 =   PageType.EditProfile;
                    break;
                }
            }
            if ( RewriteTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General CheckPageType END secured: {0}, PageId: {1}, PortalAlias:  '{2}'",
                    secured,PageId,PortalAlias),RewriteTraceSwitch.Sw.Info);
            return UrlName;
        }

        /// <summary>
		/// Format the REAL url from the parts sent, return true if PageID is a secured-register page
		/// </summary>
        public static PageType Splitter(string[] parts, StringBuilder sb, string defaultSplitter, bool pageidNoSplitter,ref string PageLoc,ref string UrlName)
		{
			//int _firstpos;
			sb.Append("?");
			int totalParts                      =   parts.GetUpperBound(0);
            PageType secured                    =   PageType.Normal;
            UrlName                             =   string.Empty;
            string PortalAlias                  =   string.Empty; // detects portalalias
			if ( pageidNoSplitter )
			{
				// last part of the array will be the page name. The pageid will be just before that.
				int pageidPosition              =   (totalParts - 1);
				for (int i = 0; i < totalParts; i++)
				{   
                    if ( string.IsNullOrEmpty(parts[i]) )
                            continue;
					if( pageidPosition == i )
					{
                        bool okParse            =   false;
                        string trimPart         =   parts[i].Trim();
                        if (( secured == PageType.Normal ) || ( secured == PageType.Special ) )
                        {
                            int PageID          =   -1;
                            okParse             =   int.TryParse(trimPart,out PageID);
                            if ( okParse )
                            {
                                int nPageID     =   PageID;
                                UrlName         =   CheckPageType(ref nPageID,ref secured,PortalAlias);
                                if ( nPageID != PageID )
                                {
                                    trimPart    =   nPageID.ToString();
                                }
                                sb.AppendFormat("pageid={0}&", trimPart);
                            }
                        }
						if ( RewriteTraceSwitch.Sw.TraceVerbose )
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General Splitter adding PageID: {0}, secured: {1}, UrlName: {2}, OkParse: {3}",
                                    new object[]{parts[i],secured,UrlName,okParse}),RewriteTraceSwitch.Sw.Info);
					}
					else
					{
                        string str          =   parts[i].Trim().ToLower().Replace(defaultSplitter, "=");
                        // detects alias to avoid a bad UniqueID later
                        if ( str.IndexOf("alias=") == 0 )
                        {
                            PortalAlias     =   str.Substring(6);
                            continue;
                        }
                        // detect page loc which means : special location for page AND take defaultPageModule as called Page
                        if ( str.IndexOf("pl=") == 0 )
                        {
                            PageLoc     =   parts[i].Trim().Replace(defaultSplitter, "=").Substring(3);
                            continue;
                        }
                        // detect page loc special which means : special location for page AND keep page name as called page
                        if ( str.IndexOf("pls=") == 0 )
                        {
                            PageLoc     =   parts[i].Trim().Replace(defaultSplitter, "=").Substring(4);
                            if ( secured == PageType.Normal )
                                secured     =   PageType.Special;
                            continue;
                        }
                        // to avoid duplication of PageId due to something like '/site/210/DefaultModulesPage.aspx?pageid=210'
                        if (str.IndexOf("pageid=") != 0)
                        {
                            sb.AppendFormat("{0}&", parts[i].Replace(defaultSplitter, "="));
                            if (RewriteTraceSwitch.Sw.TraceVerbose)
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General Splitter adding i: {0}, parts[i]: {1}", i, parts[i]), RewriteTraceSwitch.Sw.Info);
                        }
                        else
                        {
                            if (RewriteTraceSwitch.Sw.TraceVerbose)
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General Splitter removing i: {0}, parts[i]: {1}", i, parts[i]), RewriteTraceSwitch.Sw.Info);
                        }
					}
				}
			}
			else // PageSplitter present
			{
				bool found                      =	false;
				for (int i = 0; i < totalParts; i++)
				{
                    string str                  =   parts[i].ToLower().Replace(defaultSplitter, "=");
                    // detects alias to avoid a bad UniqueID later
                    if ( str.IndexOf("alias=") == 0 )
                    {
                        PortalAlias             =   str.Substring(6);
                        continue;
                    }
                     // detect page loc which means : special location for page AND take defaultPageModule as called Page
                    if ( str.IndexOf("pl=") == 0 )
                    {
                        PageLoc                 =   parts[i].Trim().Replace(defaultSplitter, "=").Substring(3);
                        continue;
                    }
                    // detect page loc special which means : special location for page AND keep page name as called page
                    if ( str.IndexOf("pls=") == 0 )
                    {
                        PageLoc                 =   parts[i].Trim().Replace(defaultSplitter, "=").Substring(4);
                        secured                 =   PageType.Special;
                        continue;
                    }
                    if (str.IndexOf("pageid=") >= 0)
					{
                        if (found)
                        {
                            if ( RewriteTraceSwitch.Sw.TraceVerbose )
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General Splitter pageidSplitter double PageId i: {0}, parts[i]: {1}'", i, parts[i]),RewriteTraceSwitch.Sw.Info);
                            continue;
                        }
                        else
                        {
                            bool okParse            =   false;
                            string[] tmp            =   str.Split(new char[]{'='},StringSplitOptions.RemoveEmptyEntries);
                            if ( tmp.GetLength(0) > 1  )
                            {
                                string trimPart     =   tmp[1].Trim();
                                if (( secured == PageType.Normal ) || ( secured == PageType.Special ) )
                                {
                                    int PageID      =   -1;
                                    okParse         =   int.TryParse(trimPart,out PageID);
                                    if ( okParse )
                                    {
                                        int nPageID =   PageID;
                                        UrlName     =   CheckPageType(ref nPageID,ref secured,PortalAlias);
                                        if ( nPageID != PageID )
                                        {
                                            trimPart=   nPageID.ToString();
                                        }
                                        parts[i]    =   string.Format("pageid={0}", trimPart);
						                found       =   true;
                                    }
                                }
                            }
                        }
						if ( RewriteTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General Splitter pageidSplitter found PageId i: {0}, parts[i]: {1}'",i,parts[i]),RewriteTraceSwitch.Sw.Info);
					}
                    sb.AppendFormat("{0}&", parts[i].Replace(defaultSplitter, "="));
					if ( RewriteTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General Splitter pageidSplitter adding i: {0}, parts[i]: {1}'",i,parts[i]),RewriteTraceSwitch.Sw.Info);
				}
			}
			
			// remove the extra &
			sb.Remove(sb.Length - 1, 1);
            return secured;
		}
		
		public static string DefaultLogonPage(string loc,string UrlName)
        {
            if (UrlName == string.Empty )
                UrlName                     =   "login.aspx";
            if ( string.IsNullOrEmpty(loc) )
                return string.Format("/{0}/{1}",Config.PortalLogonDirectory,UrlName);
            return string.Format("/{0}/{1}",loc,UrlName);
        }

		public static string DefaultLogoffPage(string loc,string UrlName)
        {
            if (UrlName == string.Empty )
                UrlName                     =   "logoff.aspx";
            if ( string.IsNullOrEmpty(loc) )
                return string.Format("/{0}/{1}",Config.PortalLogonDirectory,UrlName);
            return string.Format("/{0}/{1}",loc,UrlName);
        }
		
        public static string DefaultEditProfilePage(string loc,string UrlName)
        {
            if (UrlName == string.Empty )
                UrlName                     =   "EditProfile.aspx";
            if ( string.IsNullOrEmpty(loc) )
                return string.Format("/{0}/{1}",Config.PortalSecureDirectory,UrlName);
            return string.Format("/{0}/{1}",loc,UrlName);
        }
		
        public static string DefaultChangePwdPage(string loc,string UrlName)
        {
            if (UrlName == string.Empty )
                UrlName                     =   "ChangePwd.aspx";
            if ( string.IsNullOrEmpty(loc) )
                return string.Format("/{0}/{1}",Config.PortalSecureDirectory,UrlName);
            return string.Format("/{0}/{1}",loc,UrlName);
        }
		
        public static string DefaultRecoverPwdPage(string loc,string UrlName)
        {
            if (UrlName == string.Empty )
                UrlName                     =   "RecoverPwd.aspx";
            if ( string.IsNullOrEmpty(loc) )
                return string.Format("/{0}/{1}",Config.PortalLogonDirectory,UrlName);
            return string.Format("/{0}/{1}",loc,UrlName);
        }
		
        public static string DefaultRegisterPage(string loc,string UrlName)
        {
            if (UrlName == string.Empty )
                UrlName                     =   "Register.aspx";
            if ( string.IsNullOrEmpty(loc) )
                return string.Format("/{0}/{1}",Config.PortalLogonDirectory,UrlName);
            return string.Format("/{0}/{1}",loc,UrlName);
        }

		public static string DefaultPage
        {
            get
            {
                return Config.HandlerTargetUrl;
            }
        }

        public static string DefaultSplitter
        {
            get
            {
                return Config.HandlerDefaultSplitter;
            }
        }

        // Start Of Legacy Support Tools for previous Handler
        public static void AddAttribute(string[] parts, StringBuilder sb, int keyNumber, string attribute)
        {
            // The last one is the page so we do not consider it! (> and not >=)
            if(parts.GetUpperBound(0) > keyNumber && parts[keyNumber] != null)
            {
                sb.Append(attribute);
                sb.Append(parts[keyNumber]);
            }
        }
        
        public static void AddAttribute(StringBuilder sb, string attribute, string value)
        {
            if (!string.IsNullOrEmpty(value) )
            {
                sb.Append(attribute);
                sb.Append(value);
            }
        }

        public static void KeywordSplitter(string[] parts, StringBuilder sb, int count)
        {
            char[] _boundaryChars       =   new char[] {'1','2','3','4','5','6','7','8','9','0','_','='};

            for (int i = count; i < parts.GetUpperBound(0); i++)
            {
                sb.Append("&");
                try
                {
                    int _firstpos       =   parts[i].IndexOfAny(_boundaryChars);
                    if (_firstpos > 0)
                    {
                        if (parts[i].Substring(_firstpos,1) == "_")
                            parts[i]    =   parts[i].Substring(0,_firstpos) + "=" + parts[i].Substring(_firstpos + 1);
                        else if (parts[i].Substring(_firstpos,1) == "=")
                        {} // do nothing
                        else
                            parts[i]    =   parts[i].Insert(_firstpos,"=");
                    }
                }
                finally
                {
                    sb.Append(parts[i]);
                }
            }
        }

		/// <summary>
		/// Get all fixed url's Pages from DB or cache
		/// </summary>
        public static SortedList<int,PageNode> GetAllUrlName(string portalAlias) 
		{
            string key                          =   "GetAllUrlName";
            object ob                           =   Cache2.Get(portalAlias,key);
            if ( ob != null )
                return (SortedList<int,PageNode>)ob;
            
            SqlConnection myConnection          =   Config.GetDefSqlConnection(portalAlias);

			SqlCommand myCommand				=   new SqlCommand("dbo.adn_GetAllUrlName", myConnection);
			myCommand.CommandType				=   CommandType.StoredProcedure;
            SortedList<int,PageNode> Lst        =   new SortedList<int,PageNode>();
            SqlDataReader result				=   null;
            try
            {
                myConnection.Open();
                result							=   myCommand.ExecuteReader(CommandBehavior.CloseConnection);
                while ( result.Read() )
                {
                    PageNode pg                 =   new PageNode {PageID = (int)result[StStr.DBPageID], PageLayout=(ADNPageFlags)result[StStr.DBPageLayout], urlName=(string)result[StStr.DBUrlName]};
                    Lst.Add(pg.PageID,pg);
                }
                if ( Lst.Count > 0 )
                    Cache2.Insert(portalAlias,key, Lst, Cache2.GlobalPagesDependency(portalAlias), System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromDays(2), CacheItemPriority.Default, null);
            }
            catch (Exception exp)
            {
                if ( RewriteTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]General GetAllUrlName ex: {0}", exp),RewriteTraceSwitch.Sw.Info);
                if (result != null)
                    result.Close();
                if (myConnection.State == System.Data.ConnectionState.Open)
                    myConnection.Close();
                throw;
            }
            return Lst;
        }

        public static string GetPortalSingleCustomSettingsByAlias(string portalAlias,string settingName) 
		{
            string key                          =   string.Format("PortalSingleCustomSettings_{0}",settingName);
            object ob                           =   Cache2.Get(portalAlias,key);
            if ( ob != null )
                return (string)ob;
            
            if ( RewriteTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]General GetPortalSingleCustomSettingsByAlias portalAlias: {0}, settingName: {1}", portalAlias,settingName),RewriteTraceSwitch.Sw.Info);
            SqlConnection theCnx                =   Config.GetDefSqlConnection(portalAlias);
			SqlCommand myCommand			    =   new SqlCommand("dbo.adn_GetPortalSingleCustomSettingsByAlias", theCnx);
			myCommand.CommandType			    =   CommandType.StoredProcedure;

            SqlParameter parameterPortalAlias   =   new SqlParameter(StStr.ATPortalAlias, SqlDbType.NVarChar,50);
            parameterPortalAlias.Value          =   portalAlias;
            myCommand.Parameters.Add(parameterPortalAlias);

            SqlParameter parameterSettingName   =   new SqlParameter(StStr.ATSettingName, SqlDbType.NVarChar,50);
            parameterSettingName.Value          =   settingName;
            myCommand.Parameters.Add(parameterSettingName);

            SqlParameter parameterSettingValue  =   new SqlParameter(StStr.ATSettingValue, SqlDbType.NVarChar,1500);
            parameterSettingValue.Direction     =   ParameterDirection.Output;
            myCommand.Parameters.Add(parameterSettingValue);

            string result                       =   string.Empty;
			try
			{
				theCnx.Open();
				myCommand.ExecuteNonQuery();
                if ( parameterSettingValue.Value != DBNull.Value ) // not set ?
                    result                          =   (string)parameterSettingValue.Value;
                if ( !string.IsNullOrEmpty(result) )
                    Cache2.Insert(portalAlias,key, result, Cache2.GlobalPagesDependency(portalAlias), System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2), CacheItemPriority.Default, null);
 
			}
			catch(Exception ex)
			{
                if ( RewriteTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]General GetPortalSingleCustomSettingsByAlias ex: {0}",ex),RewriteTraceSwitch.Sw.Info);
                throw;
            }
            finally
            {
				if ( theCnx.State == System.Data.ConnectionState.Open )
					theCnx.Close();
			}
            return result;
        }
    }
}
